#include "pch.hpp"
#include "FMODDevice.hpp"
#include "FMODException.hpp"

// Memory Leak Detector
#ifdef _DEBUG
	#include <mld/mld.hpp>
#endif




FMODDevice::FMODDevice(const EngineInfo &info)
	: m_logger(info.serviceProvider->service<Logger>())
	, m_eventsystem(0)
	, m_currentAdapter(info.audioAdapter)
	, m_networking(false)
{
	m_logger->log_info("Creating FMOD software device", __FILE__, __FUNCTION__, __LINE__);

	FMOD_RESULT ret = FMOD_OK;
	UINT        version = 0;
	int         numDrivers = 0;

	/////////////////
	// Eventsystem //
	/////////////////

	// The first thing we need to do is create the system
	FMOD_API(FMOD::EventSystem_Create(&m_eventsystem));

	// Then we try to retrieve the currently installed version
	FMOD_API(m_eventsystem->getVersion(&version));
	m_logger->log_info(std::string(format("Found FMOD version 0x%x, 0x%x or higher is required") % version % FMOD_VERSION).c_str(), __FILE__, __FUNCTION__, __LINE__);

	// If it differs from our version, there is an error
	if(version < FMOD_VERSION)
		BOOSTEXT_THROW(critical_exception("The shipped FMOD version is too old"));

	// After everything's clear, we try to initialize the system
	FMOD_API(m_eventsystem->init(128, FMOD_INIT_NORMAL | FMOD_INIT_ENABLE_PROFILE, 0));

	FMOD::System *system = NULL;
	FMOD_API(m_eventsystem->getSystemObject(&system));

	// Retrieve the number of soundcards
	FMOD_API(system->getNumDrivers(&numDrivers));

	// Enumerate those cards
	char buffer[512];
	for(int i = 0; i < numDrivers; i++)
	{
		FMOD_API(system->getDriverInfo(i, buffer, sizeof(buffer), NULL));
		m_adapterList.push_back(AudioAdapter(buffer, i));
	}

	// Use the adapter, chosen by the user
	FMOD_API(system->setDriver(m_currentAdapter.index));



	//////////////////////
	// Networkingsystem //
	//////////////////////

	// Query the version supplied with the product
	FMOD_API(FMOD::NetEventSystem_GetVersion(&version));

	// Let's see if that's the right version
	if(version < FMOD_EVENT_NET_VERSION)
		BOOSTEXT_THROW(critical_exception("The shipped FMOD Networking version is too old"));

	// Okay, lets try to init the networking ability
	// If it fails, log it, but do not terminate
	ret = FMOD::NetEventSystem_Init(m_eventsystem, 0); // Listen on default port: 17997
	if(ret == FMOD_OK)
	{
		m_networking = true;
	}
	else
	{
		m_logger->log_error(QString("Failed to initialize FMOD Networking system: %1").arg(fmod_exception::readableResult(ret)),
			__FILE__,
			__FUNCTION__,
			__LINE__);
	}

	m_logger->log_info("Successfully created FMOD device:", __FILE__, __FUNCTION__, __LINE__);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

FMODDevice::~FMODDevice()
{
	// Warn the programmer (ME) if he forgot to release some interfaces
	/*if(m_projectList.size())
	{
		m_logger->log_error("Not all audio projects were released, before the AudioDevice was released",
			__FILE__,
			__FUNCTION__,
			__LINE__);

		foreach(IAudioProject* project, m_projectList)
			delete project;
	}*/


	FMOD_API(m_eventsystem->release());

	// The NetEventSystem has to be shutdown AFTER releasing the EventSystem
	if(m_networking)
		FMOD_API(FMOD::NetEventSystem_Shutdown());
}
///////////////////////////////////////////////////////////////////////////////////////////////////




QString FMODDevice::apiName() const
{
	return "FMOD";
}
///////////////////////////////////////////////////////////////////////////////////////////////////





AudioAdapters FMODDevice::queryAdapters()
{
	FMOD::System* system = NULL;
	FMOD_API(FMOD::System_Create(&system));

	BOOST_SCOPE_EXIT((system))
	{
		system->release();
	}
	BOOST_SCOPE_EXIT_END;



	// Retrieve the number of soundcards
	int numDrivers = 0;
	FMOD_API(system->getNumDrivers(&numDrivers));

	AudioAdapters adapters;
	adapters.reserve(numDrivers);

	// Enumerate those cards
	char buffer[512];
	for(int i = 0; i < numDrivers; i++)
	{
		FMOD_API(system->getDriverInfo(i, buffer, sizeof(buffer), NULL));
		adapters.push_back(AudioAdapter(buffer, i));
	}

	return adapters;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

AudioAdapters FMODDevice::adapters() const
{
	return m_adapterList;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void FMODDevice::update()
{
	FMOD_API(m_eventsystem->update());

	// Only update the networkingsystem if that started in the first place
	if(m_networking)
		FMOD_API(FMOD::NetEventSystem_Update());
}
///////////////////////////////////////////////////////////////////////////////////////////////////

/*
IAudioProject* FMODDevice::loadProject(const std::string &fname)
{
	IAudioProject *project = new FMODProject(fname, m_eventsystem);
	m_projectList.push_back(project);
	return project;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void FMODDevice::release(IAudioProject* project)
{
	if(!project)
		return;

	// If the reference is valid, the mesh has to be found in this list
	for(std::vector<IAudioProject*>::iterator i = m_projectList.begin(); i != m_projectList.end(); i++)
	{
		if((*i) == project)
		{
			m_projectList.erase(i);
			delete project;
			break;
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
*/
